// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//


#include <pollux/dwio/common/direct_decoder.h>
#include <pollux/common/base/bit_util.h>
#include <pollux/dwio/common/seekable_input_stream.h>

namespace kumo::pollux::dwio::common {
    template<bool isSigned>
    void DirectDecoder<isSigned>::seekToRowGroup(
        dwio::common::PositionProvider &location) {
        // Moves the input stream.
        IntDecoder<isSigned>::inputStream_->seekToPosition(location);
        // Forces a re-read from the stream.
        IntDecoder<isSigned>::bufferEnd_ = IntDecoder<isSigned>::bufferStart_;
        this->pendingSkip_ = 0;
    }

    template void DirectDecoder<true>::seekToRowGroup(
        dwio::common::PositionProvider &location);

    template void DirectDecoder<false>::seekToRowGroup(
        dwio::common::PositionProvider &location);

    template<bool isSigned>
    template<typename T>
    void DirectDecoder<isSigned>::nextValues(
        T *data,
        uint64_t numValues,
        const uint64_t *nulls) {
        skipPending();
        uint64_t position = 0;
        // skipNulls()
        if (nulls) {
            // Skip over null values.
            while (position < numValues && bits::isBitNull(nulls, position)) {
                ++position;
            }
        }

        // this is gross and very not DRY, but helps avoid branching
        if (position < numValues) {
            if (nulls) {
                if (!IntDecoder<isSigned>::useVInts_) {
                    if constexpr (std::is_same_v<T, int128_t>) {
                        POLLUX_NYI();
                    }
                    for (uint64_t i = position; i < numValues; ++i) {
                        if (!bits::isBitNull(nulls, i)) {
                            data[i] = IntDecoder<isSigned>::readLongLE();
                        }
                    }
                } else {
                    for (uint64_t i = position; i < numValues; ++i) {
                        if (!bits::isBitNull(nulls, i)) {
                            data[i] = IntDecoder<isSigned>::template readVInt<T>();
                        }
                    }
                }
            } else {
                if (!IntDecoder<isSigned>::useVInts_) {
                    if constexpr (std::is_same_v<T, int128_t>) {
                        POLLUX_NYI();
                    }
                    for (uint64_t i = position; i < numValues; ++i) {
                        data[i] = IntDecoder<isSigned>::readLongLE();
                    }
                } else {
                    for (uint64_t i = position; i < numValues; ++i) {
                        data[i] = IntDecoder<isSigned>::template readVInt<T>();
                    }
                }
            }
        }
    }

    template void DirectDecoder<true>::nextValues(
        int64_t *data,
        uint64_t numValues,
        const uint64_t *nulls);

    template void DirectDecoder<true>::nextValues(
        int128_t *data,
        uint64_t numValues,
        const uint64_t *nulls);

    template void DirectDecoder<false>::nextValues(
        int64_t *data,
        uint64_t numValues,
        const uint64_t *nulls);

    template void DirectDecoder<false>::nextValues(
        int128_t *data,
        uint64_t numValues,
        const uint64_t *nulls);
} // namespace kumo::pollux::dwio::common
